package dslProgramGen.loopStatementsGenerators;

import dslProgramGen.DslProgramGen;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TryToGenLoopStatementsFromContinuousSimilarLines implements LoopStatementsGenerator{
    static int lineNum = 0;
//    static int MAXNum = 0;
    public TryToGenLoopStatementsFromContinuousSimilarLines(int lineNum){
        this.lineNum = lineNum;
    }
    /**
     * 尝试对dslMethodContentList一个连续的MOP代码片段SnippetWhole（片段的开始和结束行由currentProcessedStartAndEndIndexs确定）生成Loop语句，
     * 如果代码片段SnippetWhole中有能生成Loop语句的代码片段SnippetExtract，将SnippetExtract的开始和结束下标加入到processedStartAndEndIndexsPairList，生成的Loop语句列表加入到startAndEndIndexs2LoopStatementListMap
     *
     * @param dslMethodContentList 待处理的DSL函数体
     * @param currentProcessedStartAndEndIndexs 当前想要处理的DSL函数体连续的MOP代码片段SnippetWhole的开始和结束行 index
     * @param processedStartAndEndIndexsPairList 之前已经生成过Loop语句的DSL函数体的开始行和结束行pair对 列表
     * @param startAndEndIndexs2LoopStatementListMap 之前已经生成过Loop语句的DSL函数体开始行和结束行pair对 To 对应的DSL语句列表; key表示开始行和结束行组成的String，value表示对应的Loop语句
     */
    @Override
    public void tryToGenLoopStatementInASnippet(List<String> dslMethodContentList,
                                                List<Integer> currentProcessedStartAndEndIndexs,
                                                List<List<Integer>> processedStartAndEndIndexsPairList,
                                                Map<String, List<String>> startAndEndIndexs2LoopStatementListMap) {
    //    for (int num = 1; num < MAXNum+1; num++) {
    //        lineNum = num;
            // 获得当前开始处理的行index
            int startProcessedIndex = currentProcessedStartAndEndIndexs.get(0);
            // 获得当前结束处理的行index
            int endProcessedIndex = currentProcessedStartAndEndIndexs.get(1);
            // 本次处理的内容index为 [startProcessedIndex, endProcessedIndex)
            // 若需要处理的行数小于三倍循环语句，则直接返回
            if (endProcessedIndex - startProcessedIndex < 3*lineNum) {
                return;
            }
            // 现在至少有三个需要处理的内容，对每一行dsl语句处理
            for (int currentIndex = startProcessedIndex; currentIndex < endProcessedIndex - lineNum + 1; currentIndex++) {

                // 预读下面的行
                int[] info = getInfo(dslMethodContentList, currentIndex, endProcessedIndex);
                int loopNum;
                if(info[0] < 0)
                    loopNum = 0;
                else
                    loopNum   = (info[1]-1-info[0])/info[2] + 1;

                if (loopNum > 2) {
                    // 如果之后连续的行与当前行内容一样
                    // 连续相同的行结束的index，即第一次出现不一样的行的index
                    int loopEndIndex = currentIndex + loopNum*lineNum;
                    // 生成Loop语句并将内容添加到processedStartAndEndIndexsPairList和startAndEndIndexs2LoopStatementListMap中
                    List<String> loopContent = new ArrayList<>();
                    for (int i = 0; i < lineNum; i++) {
                        loopContent.add(dslMethodContentList.get(currentIndex+i));
                    }
                    List<String> loopStatementsList = genLoopStatementsFromContinuousSimilarLines(loopContent, info);
                    processedStartAndEndIndexsPairList.add(Arrays.asList(currentIndex, loopEndIndex));
                    String mapKeyTemp = "[" + currentIndex + ", " + loopEndIndex + ")";
                    startAndEndIndexs2LoopStatementListMap.put(mapKeyTemp, loopStatementsList);
                    currentIndex = currentIndex + loopNum*lineNum - 1;
                }
            }
       // }
    }

    /**
     * 获取修改后的循环语句
     * @param loopContent 一个循环结构中的所有内容
     * @param info 循环信息，0为循环起始值，1为循环结束值，2为步长
     * @return 修改为循环的语句
     */
    public static List<String> genLoopStatementsFromContinuousSimilarLines(List<String> loopContent, int[] info) {
        // Loop(index, 0, 3, 1) {
        //	myFun(index);
        //}
        if (DslProgramGen.isGenJavaProgram) {
            List<String> loopStatements = new ArrayList<>();
            String loopHeadString = "for (int index = " + info[0] + "; " + "index < " + info[1] + "; " + "index += " + info[2]+") {";
            loopStatements.add(loopHeadString);
            for (int i =0; i<loopContent.size();i++)
                loopStatements.add("    " + loopContent.get(i).replaceAll("\\[(\\d+)]","\\[index]"));
            String loopEndString = "}";
            loopStatements.add(loopEndString);
            return loopStatements;
        } else {
            List<String> loopStatements = new ArrayList<>();
            String loopHeadString = "Loop(index, "+ info[0] +", " + info[1] + ", "+ info[2]+") {";
            loopStatements.add(loopHeadString);
            for (int i =0; i<loopContent.size();i++) {
                loopStatements.add("    " + loopContent.get(i).replaceFirst(", \\d+\\);",", index);").replaceAll("\\[(\\d+)]", "\\[index]"));
            }
            String loopEndString = "}";
            loopStatements.add(loopEndString);
            return loopStatements;
        }
    }

    /**
     * 获得当前行内容相关的循环结构信息
     * @param dslMethodContentList 待处理的DSL函数体
     * @param currentIndex 当前行在dslMethodContentList的index
     * @param endProcessedIndex 想要处理的结束行index
     * @return 循环结构信息，0为循环起始值，1为循环结束值，2为步长
     */
    public static int[] getInfo(List<String> dslMethodContentList, int currentIndex, int endProcessedIndex) {

        //返回信息
        int[] info = new int[]{-1,-1,-1};
        // 获得当前行与下一行的内容
        String[] line = new String[lineNum];
        for (int i = 0; i < lineNum; i++) {
            line[i] = dslMethodContentList.get(currentIndex+i).replaceFirst(", (\\d+)\\);",", [$1]);");
        }
        // 获取当前行数组导致的数字差异
        List<List<Integer>> allIndex = new ArrayList<>();
        List<Integer> arrayIndex = new ArrayList<>();
        allIndex.add(arrayIndex);
        Pattern pattern = Pattern.compile("\\[(\\d+)]");

        for (int i = 0; i < lineNum; i++) {
            Matcher m = pattern.matcher(line[i]);
            int num = 0;
            while (m.find()) {
                if(num ==0)
                    arrayIndex.add(Integer.valueOf(m.group(1)));
                else {
                    int value = Integer.valueOf(m.group(1));
                    if(value != arrayIndex.get(arrayIndex.size()-1)){
                        arrayIndex.add(Integer.valueOf(m.group(1)));
                    }
                }
                num++;
            }
            if(arrayIndex.size() - i == 0)
                arrayIndex.add(-1);
            else if(arrayIndex.size() - i> 1)
                return info;
        }

        //获取正则表达式
        String[] reg = new String[lineNum];
        for (int i = 0; i < lineNum; i++) {
            reg[i] = "\\Q"+line[i].replaceAll("\\[(\\d+)]","\\\\E\\\\[(\\\\d+)]\\\\Q") + "\\E";
        }
        Pattern[] patterns = new Pattern[lineNum];
        for (int i = 0; i < lineNum; i++) {
            patterns[i] = Pattern.compile(reg[i]);
        }
        //逐行匹配
        int index = currentIndex + lineNum ;
        while (index < endProcessedIndex - lineNum + 1) {
            List<Integer> temp = new ArrayList<>();
            for (int i = 0; i < lineNum; i++) {
                Matcher matcher = patterns[i].matcher(dslMethodContentList.get(index+i).replaceFirst(", (\\d+)\\);",", [$1]);"));
                int num = 0;
                while (matcher.find()){
                    if(matcher.groupCount() > 0) {
                        if(num == 0)
                            temp.add(Integer.valueOf(matcher.group(1)));
                        else {
                            int value = Integer.valueOf(matcher.group(1));
                            if(value != temp.get(temp.size()-1)){
                                temp.add(Integer.valueOf(matcher.group(1)));
                            }
                        }
                    }
                    else if(matcher.groupCount() == 0)
                        temp.add(-1);
                    num++;
                }
            }
            if (temp.size() == lineNum) {
                // 匹配成功
                allIndex.add(temp);
            } else {
                // 匹配失败
                break;
            }
            index = index + lineNum;
        }
        //有三个及以上的循环
        if(index > currentIndex + lineNum + 1)
            setInfo(info,allIndex);
        return info;
    }

    /**
     * 设置循环结构参数
     * @param info 循环结构参数，0为循环起始值，1为循环结束值，2为步长
     * @param allIndex 数字差异
     */
    public static void setInfo(int[] info, List<List<Integer>> allIndex){
        int[] line = new int[lineNum];
        for (int i = 0; i < lineNum; i++) {
            line[i] = allIndex.get(0).get(i);
        }
        int whichUseful = whichIsUseful(line);
        switch (whichUseful){
            case -2 ://其他
                return;
            case -1 : //全为与数组无关的重复语句
                info[0] = 0;
                info[1] = allIndex.size();
                info[2] = 1;
                return;
            default://包含一维数组相关重复语句
                int start = allIndex.get(0).get(whichUseful);
                int step = allIndex.get(1).get(whichUseful) - start;
                int i = 1;
                while (i < allIndex.size()) {
                    if (allIndex.get(i).get(whichUseful) - allIndex.get(i - 1).get(whichUseful) != step)
                        break;
                    i++;
                }
                if (i < 2) return;

                info[0] = start;
                info[1] = allIndex.get(i - 1).get(whichUseful) + 1;
                info[2] = step;
        }
    }

    /**
     * 判断循环的数字特征：
     * @param line 循环语句的相关数字
     * @return -2表示有不同数字，-1表示与数组无关，其余表示与数组相关的数字位置
     */
    public static int whichIsUseful(int[] line){
        Map<Integer,Integer> numMap = new HashMap<>();
        for (int i = 0; i<line.length;i++){
            int num = line[i];
            if(num != -1){
                numMap.put(num,i);
            }
        }
        switch (numMap.size()){
            case 0 :
                return -1;
            case 1 :
                for(int i:numMap.values())
                    return i;
            default:
                return -2;
        }
    }

}
